#include <stdlib.h>
#include <qwt_painter.h>
#include <qwt_plot_canvas.h>
#include <qwt_plot_marker.h>
#include <qwt_plot_curve.h>
#include <qwt_scale_widget.h>
#include <qwt_legend.h>
#include <qwt_scale_draw.h>
#include <qwt_math.h>
#include "data_plot.h"

#include <qtimer.h>
#include <qwt_plot_grid.h>
#include <qwt_plot_layout.h>
#include "scrollzoomer.h"

const unsigned int c_rangeMax = 1000;

class Zoomer: public ScrollZoomer
{
public:
    Zoomer(QwtPlotCanvas *canvas):
        ScrollZoomer(canvas)
    {
    }

    virtual void rescale()
    {
        QwtScaleWidget *scaleWidget = plot()->axisWidget(yAxis());
        QwtScaleDraw *sd = scaleWidget->scaleDraw();

        int minExtent = 0;
        if ( zoomRectIndex() > 0 )
        {
            // When scrolling in vertical direction
            // the plot is jumping in horizontal direction
            // because of the different widths of the labels
            // So we better use a fixed extent.

            minExtent = sd->spacing() + sd->majTickLength() + 1;
            minExtent += sd->labelSize(
                scaleWidget->font(), c_rangeMax).width();
        }

        sd->setMinimumExtent(minExtent);

        ScrollZoomer::rescale();
    }
};

//
//  Initialize main window
//
DataPlot::DataPlot(DataTobeShown *dataTobeShown, QWidget *parent):
    QwtPlot(parent),
    d_interval(0),
    d_timerId(-1)
{
    // Disable polygon clipping
    QwtPainter::setDeviceClipping(false);

    // We don't need the cache here
    canvas()->setPaintAttribute(QwtPlotCanvas::PaintCached, false);
    canvas()->setPaintAttribute(QwtPlotCanvas::PaintPacked, false);

#if QT_VERSION >= 0x040000
#ifdef Q_WS_X11
    /*
       Qt::WA_PaintOnScreen is only supported for X11, but leads
       to substantial bugs with Qt 4.2.x/Windows
     */
    canvas()->setAttribute(Qt::WA_PaintOnScreen, true);
#endif
#endif

    alignScales();

    //  Initialize data
    if(NULL == dataTobeShown) //No data
    {
        d_x = new double[PLOT_SIZE];
        d_y = new double[PLOT_SIZE];
        for (int i = 0; i< PLOT_SIZE; i++)
        {
            d_x[i] = i;     // time axis
            d_y[i] = 0;
       }
    }else
    {
        int dataSize = dataTobeShown->dataShown.size();
        d_x = new double[dataSize];
        d_y = new double[dataSize];
        for(int index = 0; index < dataSize; index++)
        {
            d_x[index] = index;
            d_y[index] = dataTobeShown->dataShown[index];
        }
    }

    // Assign a title
    setTitle("A Test for High Refresh Rates");
    insertLegend(new QwtLegend(), QwtPlot::BottomLegend);

    // Insert new curves
    QwtPlotCurve *cRight = new QwtPlotCurve("xls Data");
    cRight->attach(this);

    // Set curve styles
    cRight->setPen(QPen(Qt::red));

    // Attach (don't copy) data. Both curves use the same x array.
    if(NULL == dataTobeShown)
        cRight->setRawData(d_x, d_y, PLOT_SIZE);
    else
        cRight->setRawData(d_x, d_y, dataTobeShown->dataShown.size());

#if 0
    //  Insert zero line at y = 0
    QwtPlotMarker *mY = new QwtPlotMarker();
    mY->setLabelAlignment(Qt::AlignRight|Qt::AlignTop);
    mY->setLineStyle(QwtPlotMarker::HLine);
    mY->setYValue(0.0);
    mY->attach(this);
#endif//*/

    // Axis
    setAxisTitle(QwtPlot::xBottom, "Time/seconds");
    setAxisTitle(QwtPlot::yLeft, "Values");
    if(NULL == dataTobeShown)
    {
        setAxisScale(QwtPlot::xBottom, 0, PLOT_SIZE);
        setAxisScale(QwtPlot::yLeft, 0, 10);
    }
    else
    {
        setAxisScale(QwtPlot::xBottom, 0, dataTobeShown->dataShown.size());
        setAxisScale(QwtPlot::yLeft, 0, dataTobeShown->valueMax);
    }

    //setTimerInterval(0.0);
}

//
//  Set a plain canvas frame and align the scales to it
//
void DataPlot::alignScales()
{
    // The code below shows how to align the scales to
    // the canvas frame, but is also a good example demonstrating
    // why the spreaded API needs polishing.

    canvas()->setFrameStyle(QFrame::Box | QFrame::Plain );
    canvas()->setLineWidth(1);

    for ( int i = 0; i < QwtPlot::axisCnt; i++ )
    {
        QwtScaleWidget *scaleWidget = (QwtScaleWidget *)axisWidget(i);
        if ( scaleWidget )
            scaleWidget->setMargin(0);

        QwtScaleDraw *scaleDraw = (QwtScaleDraw *)axisScaleDraw(i);
        if ( scaleDraw )
            scaleDraw->enableComponent(QwtAbstractScaleDraw::Backbone, false);
    }
}

void DataPlot::setTimerInterval(double ms)
{
    d_interval = qRound(ms);

    if ( d_timerId >= 0 )
    {
        killTimer(d_timerId);
        d_timerId = -1;
    }
    if (d_interval >= 0 )
        d_timerId = startTimer(d_interval);
}

//  Generate new values
void DataPlot::timerEvent(QTimerEvent *)
{
    static double phase = 0.0;

    if (phase > (M_PI - 0.0001))
        phase = 0.0;

    // y moves from left to right:
    // Shift y array right and assign new value to y[0].

    for ( int i = PLOT_SIZE - 1; i > 0; i-- )
        d_y[i] = d_y[i-1];
    d_y[0] = sin(phase) * (-1.0 + 2.0 * double(rand()) / double(RAND_MAX));

    // update the display
    replot();

    phase += M_PI * 0.02;
}

DataPlot::~DataPlot()
{
    if(0 != d_x){
        delete d_x;
        d_x = 0;
    }
    if(0 != d_y)
    {
        delete d_y;
        d_y = 0;
    }
}
